Skip to content

20 hashlib哈希加密

你想验证下载的文件是否被篡改、存储用户密码但不想明文保存、给数据生成唯一标识……这些都要用到哈希算法。hashlib模块就是Python的哈希工具箱。

一、什么是哈希

哈希(Hash)是把任意长度的数据转换为固定长度的"指纹"。相同的数据永远产生相同的哈希值,不同的数据(几乎)永远产生不同的哈希值。

输入: "Hello" → 哈希 → 8b1f4b9b4e4e4e4e4e4e4e4e4e4e4e4e
输入: "Hello" → 哈希 → 8b1f4b9b4e4e4e4e4e4e4e4e4e4e4e4e(相同)
输入: "hello" → 哈希 → 5d41402abc4b2a76b9719d911017c592(不同)

二、常用哈希算法

2.1 MD5

python
import hashlib

# 计算MD5
data = "Hello, World!"
hash_obj = hashlib.md5(data.encode())
print(hash_obj.hexdigest())
# 65a8e27d8879283831b664bd8b7f0ad4

注意:MD5已被破解,不推荐用于安全场景,但可以用于数据校验。

2.2 SHA-256

python
import hashlib

# 计算SHA-256
data = "Hello, World!"
hash_obj = hashlib.sha256(data.encode())
print(hash_obj.hexdigest())
# dffd6021bb2bd5b0af676290809ec3a53191dd81c7f70a4b28688a362182986f

SHA-256是目前最常用的哈希算法,安全性高。

2.3 其他算法

python
import hashlib

data = "Hello, World!".encode()

# SHA-1(已被破解,不推荐)
hashlib.sha1(data).hexdigest()

# SHA-224
hashlib.sha224(data).hexdigest()

# SHA-384
hashlib.sha384(data).hexdigest()

# SHA-512
hashlib.sha512(data).hexdigest()

# SHA-3系列
hashlib.sha3_256(data).hexdigest()
hashlib.sha3_512(data).hexdigest()

# BLAKE2(推荐,比SHA-256快)
hashlib.blake2b(data).hexdigest()
hashlib.blake2s(data).hexdigest()

2.4 查看支持的算法

python
import hashlib

# 保证可用的算法
print(hashlib.algorithms_guaranteed)
# {'sha3_256', 'sha3_512', 'sha3_384', 'sha3_224', 'sha1', ...}

# 平台可用的算法(可能更多)
print(hashlib.algorithms_available)

三、分步计算

3.1 update()方法

python
import hashlib

hash_obj = hashlib.sha256()

# 分步更新
hash_obj.update(b"Hello, ")
hash_obj.update(b"World!")

print(hash_obj.hexdigest())
# 和一次性计算的结果相同

3.2 处理大文件

python
import hashlib

def file_hash(filepath, algorithm="sha256"):
    """计算文件的哈希值"""
    hash_obj = hashlib.new(algorithm)
    
    with open(filepath, "rb") as f:
        while chunk := f.read(8192):  # 每次读8KB
            hash_obj.update(chunk)
    
    return hash_obj.hexdigest()

# 使用
print(file_hash("data.txt"))

3.3 file_digest()(3.11+)

python
import hashlib

with open("data.txt", "rb") as f:
    digest = hashlib.file_digest(f, "sha256")
    print(digest.hexdigest())

四、哈希对象方法

4.1 常用方法

python
import hashlib

hash_obj = hashlib.sha256(b"Hello")

# hexdigest():返回十六进制字符串
print(hash_obj.hexdigest())

# digest():返回字节
print(hash_obj.digest())

# copy():复制哈希对象
hash_copy = hash_obj.copy()
print(hash_copy.hexdigest())  # 相同

4.2 属性

python
import hashlib

hash_obj = hashlib.sha256(b"Hello")

# digest_size:摘要大小(字节)
print(hash_obj.digest_size)  # 32

# block_size:块大小(字节)
print(hash_obj.block_size)  # 64

# name:算法名称
print(hash_obj.name)  # sha256

五、实战场景

5.1 文件完整性校验

python
import hashlib

def verify_file(filepath, expected_hash, algorithm="sha256"):
    """验证文件完整性"""
    actual_hash = file_hash(filepath, algorithm)
    return actual_hash == expected_hash

# 使用
expected = "dffd6021bb2bd5b0af676290809ec3a53191dd81c7f70a4b28688a362182986f"
if verify_file("download.zip", expected):
    print("文件完整")
else:
    print("文件被篡改")

5.2 密码存储

python
import hashlib
import os

def hash_password(password):
    """哈希密码(加盐)"""
    salt = os.urandom(32)
    hash_obj = hashlib.pbkdf2_hmac("sha256", password.encode(), salt, 100000)
    return salt + hash_obj

def verify_password(password, stored_hash):
    """验证密码"""
    salt = stored_hash[:32]
    stored_hash_obj = stored_hash[32:]
    hash_obj = hashlib.pbkdf2_hmac("sha256", password.encode(), salt, 100000)
    return hash_obj == stored_hash_obj

# 使用
hashed = hash_password("my_secret_password")
print(verify_password("my_secret_password", hashed))  # True
print(verify_password("wrong_password", hashed))       # False

5.3 数据去重

python
import hashlib

def content_hash(data):
    """计算内容哈希"""
    return hashlib.md5(data.encode()).hexdigest()

# 用哈希值去重
seen = set()
data_list = ["hello", "world", "hello", "python", "world"]

for item in data_list:
    h = content_hash(item)
    if h not in seen:
        seen.add(h)
        print(f"新数据: {item}")
    else:
        print(f"重复: {item}")

5.4 生成唯一ID

python
import hashlib
from datetime import datetime

def generate_id(prefix=""):
    """生成唯一ID"""
    data = f"{prefix}{datetime.now().isoformat()}{os.urandom(8).hex()}"
    return hashlib.md5(data.encode()).hexdigest()[:12]

print(generate_id("user"))   # a1b2c3d4e5f6
print(generate_id("order"))  # 789012345678

六、BLAKE2:更快的替代

python
import hashlib

data = b"Hello, World!"

# BLAKE2b:输出可变长(最多64字节)
hash_obj = hashlib.blake2b(data, digest_size=16)
print(hash_obj.hexdigest())  # 32个十六进制字符

# BLAKE2s:输出可变长(最多32字节)
hash_obj = hashlib.blake2s(data, digest_size=16)
print(hash_obj.hexdigest())

# BLAKE2比SHA-256快,安全性也足够

七、密钥派生函数

7.1 PBKDF2

python
import hashlib
import os

password = b"my_password"
salt = os.urandom(16)

# PBKDF2:慢哈希,防止暴力破解
dk = hashlib.pbkdf2_hmac("sha256", password, salt, 100000)
print(dk.hex())

7.2 scrypt

python
import hashlib
import os

password = b"my_password"
salt = os.urandom(16)

# scrypt:比PBKDF2更安全
dk = hashlib.scrypt(password, salt=salt, n=2**14, r=8, p=1)
print(dk.hex())

八、常见问题

8.1 编码问题

python
import hashlib

# 字符串必须编码后才能哈希
data = "你好"
# hashlib.sha256(data)  # TypeError
hashlib.sha256(data.encode("utf-8")).hexdigest()  # 正确

8.2 盐值(Salt)

python
import hashlib
import os

# 不加盐:相同密码产生相同哈希
hash1 = hashlib.sha256("password".encode()).hexdigest()
hash2 = hashlib.sha256("password".encode()).hexdigest()
print(hash1 == hash2)  # True

# 加盐:相同密码产生不同哈希
salt1 = os.urandom(16)
salt2 = os.urandom(16)
hash1 = hashlib.sha256(salt1 + "password".encode()).hexdigest()
hash2 = hashlib.sha256(salt2 + "password".encode()).hexdigest()
print(hash1 == hash2)  # False

九、总结

hashlib模块的核心:

函数用途
md5()MD5哈希(不推荐用于安全)
sha256()SHA-256哈希(推荐)
sha512()SHA-512哈希
blake2b() / blake2s()BLAKE2哈希(更快)
pbkdf2_hmac()密码哈希(加盐)
scrypt()密码哈希(更安全)

哈希对象方法:

方法用途
update(data)更新数据
hexdigest()返回十六进制字符串
digest()返回字节
copy()复制哈希对象

使用场景:

  • 文件完整性校验
  • 密码存储(加盐)
  • 数据去重
  • 生成唯一ID

安全场景用SHA-256或BLAKE2,密码存储用PBKDF2或scrypt。